use std::{cell::Cell, rc::Rc};

use common_base::{async_trait::async_trait, prelude::*, sqlx::Connection};
use common_core::{
    data::{BizMetadata, DataModel, DataObject, FormDataModel, MetadataType, TransparentDataModel},
    ServiceContext, ServiceContextBase, ServiceContextBuilder,
};
use platform_mdm_manager::MetadataManager;

use crate::context::FormContext;

pub struct FormServiceContextBuilder;

impl Default for FormServiceContextBuilder {
    fn default() -> Self {
        Self {}
    }
}

#[async_trait]
impl ServiceContextBuilder for FormServiceContextBuilder {
    async fn new_context(&self, srv_ctx_base: ServiceContextBase) -> Box<dyn ServiceContext> {
        let context = FormContext::get_instance(srv_ctx_base);
        Box::new(context)
    }

    async fn create_response(
        &self,
        srv_ctx: &mut dyn ServiceContext,
    ) -> Result<Option<Box<dyn DataModel>>> {
        let mut form_context = FormContext::downcast_from_mut(srv_ctx)?;

        let biz_id = form_context.get_value_by_param_name("MDL_ID").to_owned();

        let biz_metadata = MetadataManager::get_instance(MetadataType::Biz)
            .get_metadata(form_context.get_service_context_base_mut(), biz_id.as_str())
            .await?;
        if biz_metadata.is_none() {
            return Ok(None);
        }

        form_context.biz_metadata = biz_metadata;

        let mut form_data_model = None;
        if let Some(data_obj) = form_context
            .get_service_context_base_mut()
            .get_data_object_mut()
        {
            if let DataObject::FormDataModel(inner) = data_obj {
                form_data_model = Some(inner);
            }
        }

        if let Some(form_data_model) = form_data_model {
            form_context.form_data_model = Some(Rc::clone(form_data_model));
            Ok(Some(Box::new(TransparentDataModel::default())))
        } else {
            todo!()
        }
    }

    async fn finish_context(&self, srv_ctx: &mut dyn ServiceContext) -> Result<()> {
        if let Some(conn) = srv_ctx.take_connection() {
            conn.close().await?
        }
        Ok(())
    }
}
